//
//   textReader.app -  kludged up by Jim Beesley
//   This incorporates inspiration, code, and examples from (among others)
//   * The iPhone Dev Team for toolchain and more!
//   * James Yopp for the UIOrientingApplication example
//   * Paul J. Lucas for txt2pdbdoc
//   * http://iphonedevdoc.com/index.php - random hints and examples
//   * mxweas - UITransitionView example
//   * thebends.org - textDrawing example
//   * Books.app - written by Zachary Brewster-Geisz (and others)
//   * "iPhone Open Application Development" by Jonathan Zdziarski - FileTable/UIDeletableCell example
//   * http://garcya.us/ - for application icons
//   * Allen Li for help with rotation lock and swipe/gestures
//
//   This program is free software; you can redistribute it and/or
//   modify it under the terms of the GNU General Public License
//   as published by the Free Software Foundation; version 2
//   of the License.
//
//   This program is distributed in the hope that it will be useful,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   GNU General Public License for more details.
//
//   You should have received a copy of the GNU General Public License
//   along with this program; if not, write to the Free Software
//   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//


#import "textReader.h"
#import "MyTextView.h"
#import "MyPreferencesTable.h"









@interface textReader(hidden)
- (void) showStatusBar:(ShowStatus)ss;
- (void)showSliderLocation;
@end

// *****************************************************************************
// This is the "main" GUI application ...
@implementation textReader
@synthesize orientationLocked;
@synthesize fileTable = _fileTable;
@synthesize textView;
- (id) init {
	
	self = [super init];

    defaults = [[NSUserDefaults standardUserDefaults] retain];

    currentOrientation  = -9999;
    wait                = nil;
    baseTextView        = nil;
    textView            = nil;
    _fileTable           = nil;
    prefsTable          = nil;
    navBar              = nil;
    slider              = nil;
    toolBar             = nil;
    searchBox           = nil;
    lastSearch          = nil;
    coverArt            = nil;
    openname            = nil;
    openpath            = nil;
    currentView         = My_No_View;
    showStatus          = ShowStatus_Off;
    showCoverArt        = false;
    fileScroll          = FileScroll_Off;
    searchWrap          = false;
    searchWord          = false;
    deleteCacheDir      = false;
	return self;
} // init




- (void) setDeleteCacheDir:(bool)dcd { deleteCacheDir = dcd; }
- (bool) getDeleteCacheDir { return deleteCacheDir; }

- (void) setSearchWrap:(bool)sw {searchWrap = sw; }
- (bool) getSearchWrap { return searchWrap; }

- (void) setSearchWord:(bool)sw { searchWord = sw; }
- (bool) getSearchWord { return searchWord; }




- (UIInterfaceOrientation)getOrientation
{
	return [[UIApplication sharedApplication] statusBarOrientation];
}

- (ShowStatus) getShowStatus {
    return showStatus;
} // getShowStatus


// Remember the new status bar setting
- (void) setShowStatus:(ShowStatus)ss {
    showStatus = ss;
} // setShowStatus




// Get rect of rotated window
- (struct CGRect) getOrientedViewRect {
    struct CGRect FSrect;

    // 0==horizontal(portrait), 90/-90==vertical(landscape)
    if (UIInterfaceOrientationIsLandscape([self getOrientation]))
        FSrect = CGRectMake(0, 0, 480, 320);
    else
        FSrect = CGRectMake(0, 0, 320, 480);

    return FSrect;
} // getOrientedViewRect


// Get height and width in rotated window
- (struct CGSize) getOrientedViewSize {
    return [self getOrientedViewRect].size;
} // getOrientedViewSize


- (void) showWait {

    if (!wait)
    {
        struct CGRect rect = [self getOrientedViewRect];
        rect.origin.x = 0;
        rect.origin.y = rect.size.height - (rect.size.height * 2) / 5;
        rect.size.height = rect.size.height / 5;

        wait = [[MBProgressHUD alloc] initWithWindow:mainWindow];
		[mainWindow addSubview:wait];
        [wait setLabelText:_T(@"Loading ...")];
        // [wait setText:@""];
        //[wait drawRect:rect];
        //[wait setNeedsDisplay];

        // Sad - doesn't work ...
        // Try to hide the background of the spinner ...
        // float backParts[4] = {0, 0, 0, .5};
        // float backParts[4] = {0, 0, 0, 0};
        // CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        // [wait setBackgroundColor: CGColorCreate(colorSpace, backParts)];
    }

// JIMB BUG BUG - handle this !!!
    // Rotate ?!?!?!? Not sure how best to do it ????
    [wait show:YES];

} // showWait


- (void) hideWait {
  if (wait)
  {
      [wait show:NO];
      [wait removeFromSuperview];
      [wait release];
      wait = nil;
  }
} // hideWait


- (void) setShowCoverArt:(bool)show {
    showCoverArt = show;
} // setShowCoverArt


- (bool) getShowCoverArt { return showCoverArt; };


- (MyViewName) getCurrentView { return currentView; };


- (NSString*) getFileName {
    return [textView getFileName];
}

- (NSString*) getFilePath {
    return [textView getFilePath];
}

- (void) removeDefaults:(NSString*)name {
    if (name)
    {
        // Remove start char for this file
        [defaults removeObjectForKey:name];

        // If this is the current open file, remove the OpenFileName entry
        // so we won't get an error when we exit and start
        if ([name isEqualToString:[defaults stringForKey:TEXTREADER_OPENFILE]])
        {
            [defaults removeObjectForKey:TEXTREADER_OPENPATH];
            [defaults removeObjectForKey:TEXTREADER_OPENFILE];
        }
    }
} // removeDefaults


// Write current preferences and clean up
- (void)applicationWillTerminate:(UIApplication *)application
{

//  // Restore original volume
//  AVSystemController *avsc = [AVSystemController sharedAVSystemController];
//  if (curVol != initVol)
//  {
//      // Wish there was a way to restore the vol w/o having the volume
//      // HUD appear when we exit ?!?!?!?!? Leave it out for now ...
//      curVol = initVol;
//      [avsc setActiveCategoryVolumeTo:initVol];
//  }
//
//    [defaults setInteger:[textView getInvertColors] forKey:TEXTREADER_INVERTCOLORS];
//
//    [defaults setInteger:[textView getCacheAll] forKey:TEXTREADER_CACHEALL];
//
//    [defaults setInteger:[self getOrientCode] forKey:TEXTREADER_OCODE];
//    [defaults setInteger:[self orientationLocked] forKey:TEXTREADER_OLOCKED];
//
//    [defaults setInteger:reverseTap forKey:TEXTREADER_REVERSETAP];
//
//    [defaults setInteger:showCoverArt forKey:TEXTREADER_SHOWCOVERART];
//
//    [defaults setInteger:fileScroll forKey:TEXTREADER_FILESCROLL];
//
//    [defaults setInteger:deleteCacheDir forKey:TEXTREADER_DELETECACHEDIR];
//
//    [defaults setInteger:searchWrap forKey:TEXTREADER_SEARCHWRAP];
//    [defaults setInteger:searchWord forKey:TEXTREADER_SEARCHWORD];
//
//    [defaults setInteger:swipeOK forKey:TEXTREADER_SWIPE];
//
//    [defaults setInteger:rememberURL forKey:TEXTREADER_REMEMBERURL];
//
//    [defaults setInteger:showStatus forKey:TEXTREADER_SHOWSTATUS];
//
//    [defaults setInteger:volScroll forKey:TEXTREADER_VOLSCROLL];
//
//    [defaults setInteger:[textView getIgnoreSingleLF] forKey:TEXTREADER_IGNORELF];
//
//    [defaults setInteger:[textView getPadMargins] forKey:TEXTREADER_PADMARGINS];
//
//    [defaults setObject:[textView getBkgImage] forKey:TEXTREADER_BKGIMAGE];
//
//    [defaults setInteger:[textView getFontZoom] forKey:TEXTREADER_FONTZOOM];
//
//    [defaults setInteger:[textView getIndentParagraphs] forKey:TEXTREADER_INDENT];
//
//    [defaults setInteger:[textView getRepeatLine] forKey:TEXTREADER_REPEATLINE];
//
//    [defaults setInteger:[textView getTextAlignment] forKey:TEXTREADER_TEXTALIGNMENT];
//
//    [defaults setObject:[textView getFont] forKey:TEXTREADER_FONT];
//
    [defaults setInteger:[textView getFontSize] forKey:TEXTREADER_FONTSIZE];
//
//    [defaults setInteger:[textView getEncodings][0] forKey:TEXTREADER_ENCODING];
//    [defaults setInteger:[textView getEncodings][1] forKey:TEXTREADER_ENCODING2];
//    [defaults setInteger:[textView getEncodings][2] forKey:TEXTREADER_ENCODING3];
//    [defaults setInteger:[textView getEncodings][3] forKey:TEXTREADER_ENCODING4];
//
//    [defaults setFloat:[textView getTextColors].text_red   forKey:TEXTREADER_TEXTRED];
//    [defaults setFloat:[textView getTextColors].text_green forKey:TEXTREADER_TEXTGREEN];
//    [defaults setFloat:[textView getTextColors].text_blue  forKey:TEXTREADER_TEXTBLUE];
//
//    [defaults setFloat:[textView getTextColors].bkg_red   forKey:TEXTREADER_BKGRED];
//    [defaults setFloat:[textView getTextColors].bkg_green forKey:TEXTREADER_BKGGREEN];
//    [defaults setFloat:[textView getTextColors].bkg_blue  forKey:TEXTREADER_BKGBLUE];

    // Save lastSearch if we have one ...
    if (lastSearch)
        [defaults setObject:lastSearch forKey:TEXTREADER_LASTSEARCH];

    // Save currently open book so we can reopen it later
    NSString * fileName = [textView getFileName];
    if (!fileName)
        fileName = @"";

    NSString * filePath = [textView getFilePath];
    if (!filePath)
        filePath = TEXTREADER_DEF_PATH;

    [defaults setObject:fileName forKey:TEXTREADER_OPENFILE];
    [defaults setObject:filePath forKey:TEXTREADER_OPENPATH];
    //[self setDefaultStart:fileName start:[textView getStart]];

} // applicationWillSuspend


- (int) getDefaultStart:(NSString*)name {

    int pos = 0;

    if (name)
        pos = [defaults integerForKey:name];

    return pos;

} // getDefaultStart


- (void) setDefaultStart:(NSString*)name start:(int)startChar {

    [defaults setInteger:startChar forKey:name];

} // setDefaultStart



- (void) fixButtons {

	UIToolbar *toolbar3 = navigationController.toolbar;
	toolbar3.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
	toolbar3.barStyle = UIBarStyleBlackTranslucent;
	
	
	percent = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 416.0, 280.0, 21.0)];
	percent.frame = CGRectMake(20.0, 0, 280.0, 21.0);
	percent.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin
								 | UIViewAutoresizingFlexibleHeight;
	percent.numberOfLines = 1;
	percent.text = @"Label";
	percent.textAlignment = UITextAlignmentCenter;
	percent.textColor = [UIColor whiteColor];
	percent.backgroundColor = [UIColor clearColor];
	
	slider = [[UISlider alloc] initWithFrame:CGRectMake(12.0, 55.0, 298.0, 23.0)];
	slider.frame = CGRectMake(12.0, 21, 298.0, 23.0);
	slider.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
	slider.continuous = YES;
	slider.multipleTouchEnabled = NO;
	[slider addTarget:self action:@selector(swipeSlider:) forControlEvents:UIControlEventValueChanged];
	[slider addTarget:self action:@selector(handleSlider:) forControlEvents:UIControlEventTouchUpInside];
	
	UIButton *button13 = [UIButton buttonWithType:UIButtonTypeCustom];
	button13.frame = CGRectMake(275.0, 0.0, 37.0, 37.0);
	button13.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
	
	
	[toolbar3 addSubview:button13];
	[toolbar3 addSubview:slider];
	[toolbar3 addSubview:percent];
	

} // fixButtons


- (void) loadDefaults {

	/*
    // Restore general prefs
    [textView setInvertColors:[defaults integerForKey:TEXTREADER_INVERTCOLORS]];

    [textView setCacheAll:[defaults integerForKey:TEXTREADER_CACHEALL]];

    [self setReverseTap:[defaults integerForKey:TEXTREADER_REVERSETAP]];

    [self setShowCoverArt:[defaults integerForKey:TEXTREADER_SHOWCOVERART]];

    [self setFileScroll:[defaults integerForKey:TEXTREADER_FILESCROLL]];

    [self setDeleteCacheDir:[defaults integerForKey:TEXTREADER_DELETECACHEDIR]];

    [self setSearchWrap:[defaults integerForKey:TEXTREADER_SEARCHWRAP]];
    [self setSearchWord:[defaults integerForKey:TEXTREADER_SEARCHWORD]];

    [self setSwipeOK:[defaults integerForKey:TEXTREADER_SWIPE]];

    [self setRememberURL:[defaults integerForKey:TEXTREADER_REMEMBERURL]];

    [self setShowStatus:[defaults integerForKey:TEXTREADER_SHOWSTATUS]];

    //[self setVolScroll:[defaults integerForKey:TEXTREADER_VOLSCROLL]];

    [textView setIgnoreSingleLF:[defaults integerForKey:TEXTREADER_IGNORELF]];

    [textView setPadMargins:[defaults integerForKey:TEXTREADER_PADMARGINS]];

    [textView setBkgImage:[defaults stringForKey:TEXTREADER_BKGIMAGE]];

    [textView setFontZoom:[defaults integerForKey:TEXTREADER_FONTZOOM]];

    [textView setIndentParagraphs:[defaults integerForKey:TEXTREADER_INDENT]];

    [textView setRepeatLine:[defaults integerForKey:TEXTREADER_REPEATLINE]];

    [textView setTextAlignment:[defaults integerForKey:TEXTREADER_TEXTALIGNMENT]];
	 */
    // Restore font prefs
    int fontSize = [defaults integerForKey:TEXTREADER_FONTSIZE];
    if (fontSize < 8 || fontSize > 40)
        fontSize = TEXTREADER_DFLT_FONTSIZE;

    NSString * font = [defaults stringForKey:TEXTREADER_FONT];
    if (!font || [font length] < 1)
        font = TEXTREADER_DFLT_FONT;

    [textView setFont:font size:fontSize];

    NSStringEncoding   encodings = [defaults integerForKey:TEXTREADER_ENCODING];
    [textView setEncodings:encodings];

    MyColors txtcolors;

    txtcolors.text_red   = [defaults floatForKey:TEXTREADER_TEXTRED];
    txtcolors.text_green = [defaults floatForKey:TEXTREADER_TEXTGREEN];
    txtcolors.text_blue  = [defaults floatForKey:TEXTREADER_TEXTBLUE];

    txtcolors.bkg_red    = [defaults floatForKey:TEXTREADER_BKGRED];
    txtcolors.bkg_green  = [defaults floatForKey:TEXTREADER_BKGGREEN];
    txtcolors.bkg_blue   = [defaults floatForKey:TEXTREADER_BKGBLUE];

    [textView setTextColors:&txtcolors];

    // Get the last search string requested ...
    lastSearch = [defaults stringForKey:TEXTREADER_LASTSEARCH];

    // Open last opened file at last position
    NSString * path = [defaults stringForKey:TEXTREADER_OPENPATH];
    NSString * name = nil; [defaults stringForKey:TEXTREADER_OPENFILE];
    if (name && [name length])
        [self openFile:name path:path];
        // Leave wait up - openfile will clear it when done
    else
    {
        // No file to open - switch to info view

        // Done waiting
        [self hideWait];
    }

} // loadDefaults


// Set the filename as the navbar title
- (void) setNavTitle {

    // Create title label ...
	UINavigationItem *navigationItem = navigationController.navigationItem;
    if ([textView getFileName])
    {
        if ([self getFileType:[textView getFileName]] == kTextFileTypeTRCache)
            [navigationItem setPrompt:[[[textView getFileName] stringByDeletingPathExtension] stringByDeletingPathExtension]];
        else
            [navigationItem setPrompt:[[textView getFileName] stringByDeletingPathExtension]];
    }
    else
        [navigationItem setPrompt:TEXTREADER_NAME];

} // setNavTitle


- (void) recreateSlider 
{
	// CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
	
	if ([textView getText] && [[textView getText] length])
	{
		// Create the slider ...
		//[slider setAlpha:0.5];
		slider.minimumValue = 0.0;
		slider.maximumValue = [[textView getText] length]-1;
		slider.value = [textView getStart];
	}
	
	// Make sure the navbar title is the filename ...
	[self setNavTitle];
	
} // recreateSlider

// We get this message when the slider is touched up
- (IBAction) handleSlider: (id)control
{
	[textView setStart:slider.value];
	[self showLocation];	
} // handleSlider

// We get this message when the slider is moved/touched
- (IBAction) swipeSlider: (id)control
{
	[self showSliderLocation];
} // swipeSlider


- (void)showSliderLocation
{
	NSString * pct = nil;
	pct = [NSString stringWithFormat:@"Location %d", (int)slider.value];
	[percent setText:pct];
}//showSliderLocation
- (void) showLocation 
{
	NSString * pct = nil;
	
	if ([textView getText] && [[textView getText] length])
	{
		pct = [NSString stringWithFormat:@"Location %d", [textView getStart]];
	}
	else
	{
		// pct = TEXTREADER_NAME;
		pct = @"";
	}
	
	[percent setText:pct];
	
} // showLocation


// Gets rid of the search box ...
- (void) endSearch {

    // Kill the search box
    if (searchBox)
    {
        [searchBox removeFromSuperview];
        [searchBox release];
    }
    searchBox = nil;


    // Restore the nav title ...
    [self setNavTitle];

} // endSearch

- (void) showStatusBar:(ShowStatus)ss {
	
    //curStatus = ss;
    switch (ss)
    {
        case ShowStatus_Off:
			[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:YES];
            [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
            break;
        case ShowStatus_Dark:
            [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:YES];
            [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
            break;
        default:
        case ShowStatus_Light:
            [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:YES];
            [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
            break;
    }
	
} // showStatus
- (void) showView:(MyViewName)viewName
{
    // Get rid of the search stuff
    [self endSearch];

    switch (viewName)
    {
        case My_No_View:
            break;

        case My_Color_View:
            break;

        case My_Download_View:
            if (currentView != My_Download_View)
            {
            }
            break;

        case My_Text_Prefs_View:
        case My_Display_Prefs_View:
        case My_Scroll_Prefs_View:
        case My_Other_Prefs_View:
        case My_Prefs_View:
            break;
        case My_File_View:
            break;

        case My_Info_View:
			
			if ([navigationController isNavigationBarHidden]) //if navigation bar is hiding, show it
			{
				navigationController.navigationBarHidden = NO;
				navigationController.toolbarHidden = NO;

			}
			else //if is showing, hide it
			{
				navigationController.navigationBarHidden = YES;
				navigationController.toolbarHidden = YES;
			}

            break;

        case My_Text_View:
            if (currentView != My_Text_View)
            {
                // Rescale in case of rotation
                [self showStatusBar:showStatus];

                // Hide navbar and title
                navigationController.navigationBarHidden = YES;

                // Switch views
				[baseTextViewController didRotateFromInterfaceOrientation:UIInterfaceOrientationPortrait];
				[navigationController pushViewController:baseTextViewController animated:YES];
                currentView = My_Text_View;


                _fileTable = nil;
                prefsTable = nil;

                [self redraw];
            }
            break;

    } // switch on viewName

} // showView


// Handle the search button
- (void)showSearch
{
    CGRect FSrect = [self getOrientedViewRect];
    CGRect searchRect = CGRectMake(0., 35., FSrect.size.width, 30);

    // Only search if we are not already searching, and there is text to search through
    if (!searchBox &&
        [textView getText] && [[textView getText] length])
    {
        searchBox = [[UISearchBar alloc] initWithFrame:searchRect];
        [searchBox setDelegate:self];

        searchBox.placeholder = _T(@"Enter your search text ...");
        [navBar addSubview:searchBox];

        if (lastSearch)
            searchBox.text = lastSearch;

        // Set focus to search
        [searchBox becomeFirstResponder];
    }

} // showSearch

- (void)backToFileTable
{
	[self showStatusBar:ShowStatus_Light];
	currentView = My_No_View;
	[navigationController popViewControllerAnimated:YES];
	navigationController.navigationBarHidden = YES;
	navigationController.toolbarHidden = YES;
}
- (NSRange) findText:(NSString *)str range:(NSRange)cur {

        NSRange found;

DoSearch:
        found = [[textView getText] rangeOfString:str
                                          options:NSCaseInsensitiveSearch
                                            range:cur];

        // Do we need to make sure that this is not a substring of another word?
        if (searchWord && found.location != NSNotFound)
        {
            unichar prev = 0x00;
            unichar next = 0x00;

            // Check char before and after, and make sure it isn't a letter ...
            if (found.location && found.location < [[textView getText] length]-1)
            {
                prev = [[textView getText] characterAtIndex:found.location-1];
                if ([textView isBlank:found.location-1] ||
                    [textView isLF:found.location-1] ||
                    [textView isPunct:found.location-1])
                   prev = 0x00;
            }
            if (found.location+found.length < [[textView getText] length])
            {
                next = [[textView getText] characterAtIndex:found.location+found.length];
                if ([textView isBlank:found.location+found.length] ||
                    [textView isLF:found.location+found.length] ||
                    [textView isPunct:found.location+found.length])
                   next = 0x00;
            }
            if (prev || next)
            {
                // Bummer ... this is part of a larger word
                // Start searching from location+1
                cur.length   = MAX(0, (int)cur.length - (((int)found.location - (int)cur.location) + 1));
                cur.location = found.location+1;

                // Make sure we have not gone past the end ...
                if (cur.location + cur.length > [[textView getText] length])
                {
                    found.location = NSNotFound;
                    found.length   = 0;
                }
                else
                    goto DoSearch;
            }
        }

        return found;

} // findText


- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
//- (void) searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
    // Save the new search string
    if (lastSearch)
        [lastSearch release];

    // Get the new search text
    lastSearch = [searchBox.text copy];

    // OK - try to find it in the current text starting at the current position ...
    NSRange cur = {MIN((int)[textView getStart]+1,
                       (int)[[textView getText] length]-1),
                   MAX(0,
                       (int)[[textView getText] length] - ((int)[textView getStart] + 1))};

    NSRange found = [self findText:lastSearch range:cur];

    // Wrap search?
    if (found.location == NSNotFound && searchWrap)
    {
        // Search from begining to current location
        cur.location = 0;
        cur.length   = MIN( (int)[[textView getText] length]-1,
                            (int)[textView getStart]+(int)[lastSearch length] );

        found = [self findText:lastSearch range:cur];
    }

    if (found.location == NSNotFound)
    {
        // Set text to not found
        //[navBar ti:_T(@"Search text not found ...")];
    }
    else
    {
        // Set new start position
        [textView setStart:found.location];

        // Get rid of the search stuff
        [self endSearch];

        // Show the user where we found the text
        [self showView:My_Text_View];
    }

} // searchBarTextDidEndEditing




// // The keyboard is used for searching ...
// -(BOOL) keyboardInput:(id)k shouldInsertText:(id)i isMarkedText:(int)b {
//
//     if ([i length] == 1 && [i characterAtIndex:0] == 0xA)
//     {
//         // Save the new search string
//         if (lastSearch)
//             [lastSearch release];
//
//         // Get the new search text
//         lastSearch = [[searchBox text] copy];
//
//         // OK - try to find it in the current text starting at the current position ...
//         NSRange cur = {MIN((int)[textView getStart]+1,
//                            (int)[[textView getText] length]-1),
//                        MAX(0,
//                            (int)[[textView getText] length] - ((int)[textView getStart] + 1))};
//
//         NSRange found = [self findText:lastSearch range:cur];
//
//         // Wrap search?
//         if (found.location == NSNotFound && searchWrap)
//         {
//             // Search from begining to current location
//             cur.location = 0;
//             cur.length   = MIN( (int)[[textView getText] length]-1,
//                                 (int)[textView getStart]+(int)[lastSearch length] );
//
//             found = [self findText:lastSearch range:cur];
//         }
//
//         if (found.location == NSNotFound)
//         {
//             // Set text to not found
//             [navBar setPrompt:_T(@"Search text not found ...")];
//         }
//         else
//         {
//             // Set new start position
//             [textView setStart:found.location];
//
//             // Get rid of the search stuff
//             [self endSearch];
//
//             // Show the user where we found the text
//             [self showView:My_Text_View];
//         }
//
//        return NO;
//     }
//
//     return YES;
// } // keyboardInput


- (IBAction)toggleLock:(id)sender
{
    if ([self orientationLocked])
        orientationLocked = FALSE;
    else
        orientationLocked = TRUE;

} // toggleLock


// Displays an alert sheet dialog with an optional button
// NOTE: If no button specified, caller is responsible for releasing it!
- (void) showDialog:(NSString*)title  msg:(NSString*)msg  buttons:(DialogButtons)buttons
{
	UIAlertView *okDialog = nil;
	if (!okDialog)
	{
		
		// Display the requested dialog
		NSString *buttonTitle;
		if (buttons & DialogButtons_OK)
			buttonTitle = _T(@"OK");
		if (buttons & DialogButtons_Website)
			buttonTitle = _T(@"Visit Website");
		
		if (buttons & DialogButtons_DeleteCache)
		{            
			buttonTitle = _T(@"Keep Original File");
			buttonTitle = _T(@"Delete Original File");
		}
		
		okDialog = [[UIAlertView alloc] initWithTitle:title
											  message:msg
											 delegate:nil
									cancelButtonTitle:buttonTitle
									otherButtonTitles:nil];
		[okDialog show];
		[okDialog release];
	}    
	
} // showOKDialog






// This is called when everything is ready to go/initialized
// Now we can set up the GUI and get to work
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{


    struct CGRect FSrect = [self getOrientedViewRect];


    // Fire up the loading wait msg
    //[self showWait];

	[self.fileTable setTextReader:self];
	
	
    // Create a view to hold the scrolling text, slider and navBar
    baseTextView = [[[UIView alloc] initWithFrame: FSrect] retain];
    [baseTextView setAutoresizingMask:kMainAreaResizeMask];


    // Go ahead and create the text view window we will
    // draw text onto ... that way we know it always exists
    textView = [[[MyTextView alloc] initWithFrame: FSrect] retain];
    [textView setAutoresizingMask: kMainAreaResizeMask];
    [textView setTextReader:self];
    [baseTextView addSubview:textView];

	
	baseTextViewController = [[MyTextViewController alloc] init];
	baseTextViewController.trApp = self;
	baseTextViewController.view = baseTextView;
	baseTextViewController.textView = textView;

    // Create nav bar for info view
		navBar  = navigationController.navigationBar;

	
	//hide navigation bar in file table view
	navigationController.navigationBarHidden = YES;

    [self fixButtons];


    [self loadDefaults];

	[mainWindow addSubview:navigationController.view];
    [mainWindow makeKeyAndVisible];
	
    return YES;

} // applicationDidFinishLaunching



- (void) scaleCoverArt {

    if (coverArt)
    {
        struct CGRect rect = [self getOrientedViewRect];
       // int yOffset = showStatus ? [UIHardware statusBarHeight] : 0;

        // This will return the rect taking into account the
        // status bar if present ... this means the image will not
        // be cropped by the status bar
        rect = [textView getOrientedViewRect];

        //[self scaleImage:coverArt maxheight:rect.size.height maxwidth:rect.size.width yOffset:yOffset];
    }

} // scaleCoverArt


// Figure out point location in rotated window
- (CGPoint)getOrientedPoint:(CGPoint)loc {
    struct CGSize viewSize = [self getOrientedViewSize];
    int angle = [self getOrientation];

    // coordinates are correct for orientation==0
    if (angle == 90) // on right side
        loc = CGPointMake(loc.y, viewSize.height - loc.x);
    else if (angle == -90) // on left side
        loc = CGPointMake(viewSize.width - loc.y, loc.x);

    return loc;
} // getOrientedEventLocation





- (void) clearCoverArt {
    if (coverArt)
    {
        [coverArt removeFromSuperview];
        // [coverArt release];
        coverArt = nil;

        // // Restore the transview ...
        // [mainWindow setContentView:transView];
     }
} // clearCoverArt


// Display cover art for file if requested - if it exists
- (void) showCoverArt:(NSString *)name path:(NSString *)path {

    NSString * iname = [self getCoverArt:name path:path];

    if (iname)
    {
        UIImage * image = [UIImage imageNamed:path];

        coverArt = [[UIImageView alloc] initWithImage:image];

        // Scale the image for the screen ...
        [self scaleCoverArt];

        // Putting it on the base text view means it will appear over the text
        [baseTextView addSubview:coverArt];

        // Putting it on the transview means it will disappear when the text appears
        // [transView addSubview:coverArt];
        // Putting it in the window contents means we'll have rotation problems
        // with the other views unless we do a lot of extra work ...
        // [mainWindow setContentView:coverArt];
    }

} // showCoverArt



// Returns true if we can open this file
- (bool) isVisibleFile:(NSString*)file path:(NSString*)path {

    NSString     * fullpath = [path stringByAppendingPathComponent:file];
    TextFileType   fType    = [self getFileType:file];
    BOOL           isDir    = false;

    // A file is visible if it is a supported type
    // Cached directories are also visible
    if (!fType)
        return false;

    // Not visible if it doesn't exist
    if (![[NSFileManager defaultManager]
          fileExistsAtPath:fullpath
          isDirectory:&isDir])
       return false;

    // Visible if it is a cache file
    if (fType == kTextFileTypeTRCache)
       return true;

    // Directories are not visible "files"
    if (isDir)
       return false;

    // If this file has a cache file, it is not visible
    if ([[NSFileManager defaultManager]
         fileExistsAtPath:[fullpath
                            stringByAppendingPathExtension:TEXTREADER_CACHE_EXT] isDirectory:&isDir])
       return false;

    // Otherwise, this is visible
    return true;

} // isVisibleFile




// Force a resize/redraw as needed
- (void) redraw {

    switch (currentView)
    {
        case My_Text_Prefs_View:
        case My_Display_Prefs_View:
        case My_Scroll_Prefs_View:
        case My_Other_Prefs_View:
        case My_Prefs_View:
            //[prefsTable resize];
            break;
        case My_Color_View:

            break;
        case My_File_View:
           // [fileTable resize];
            break;
        case My_Download_View:

            break;
        default:
        case My_Text_View:
        case My_Info_View:
            [textView setNeedsDisplay];
            break;
    }

} // redraw


// Do the actual load - we split this out so we can show the wait hud ...
// What a waste - the HUD code ought to work without needing messages on the
// main thread
- (void) openFile2
{
    if (openname && [textView openFile:openname path:openpath])
        [self showView:My_Text_View];
    else
        [self showView:My_Info_View];

    [self hideWait];

} // openFile2


// Only purpose is a wrapper for openFile2 - we have to do it on the main thread
// or it will choke!
- (void) thrdOpenFile:(id)ignored
{
    [self performSelectorOnMainThread:@selector(openFile2)
                            withObject:nil waitUntilDone:YES];
} // thrdOpenFile


- (void) rememberOpenFile:(NSString*)name path:(NSString*)path {

    if (openname)
        [openname release];
    if (openpath)
        [openpath release];

    openname = [name copy];
    openpath = [path copy];

} // rememberOpenFile


// Close currently open file
- (void) closeCurrentFile {

   [textView closeCurrentFile];

   [self redraw];

} // closeCurrentFile


// NOTE: We use a thread because otherwise the loading hud won't show up
//       Opening on a thread slows us down, so this is a case where
//       listening to users slows things down even more
//       (kind of like scrolling)
- (void) openFile:(NSString *)name path:(NSString *)path {

    // Disable any future scrolling ...
    //[textView endDragging];

    [self showCoverArt:name path:path];

    [self showWait];

    // Remember the open file and path
    [self rememberOpenFile:name path:path];

    // For some reason, we often don't get the "wait" when loading default file
    // Maybe because the mainwindow isn't quite up?!?!?
    [NSThread detachNewThreadSelector:@selector(thrdOpenFile:)
                             toTarget:self
                           withObject:nil];

} // openFile


// Figure out a type for the specified file based on the extension
- (TextFileType) getFileType:(NSString*)fileName {

    TextFileType type = kTextFileTypeUnknown;

    if ([fileName length] > 4 &&
        [fileName characterAtIndex:[fileName length]-4] == '.')
    {
        NSString * ext = [fileName substringFromIndex:[fileName length]-3];

        if (![ext compare:@"txt" options:kCFCompareCaseInsensitive ])
            type = kTextFileTypeTXT;

        else if (![ext compare:@"pdb" options:kCFCompareCaseInsensitive ] ||
                 ![ext compare:@"prc" options:kCFCompareCaseInsensitive ])
            type = kTextFileTypePDB;

        else if (![ext compare:@"htm" options:kCFCompareCaseInsensitive ])
            type = kTextFileTypeHTML;

        else if (![ext compare:@"fb2" options:kCFCompareCaseInsensitive ])
            type = kTextFileTypeFB2;

        else if (![ext compare:@"rtf" options:kCFCompareCaseInsensitive ])
            type = kTextFileTypeRTF;

        else if (![ext compare:@"chm" options:kCFCompareCaseInsensitive ])
            type = kTextFileTypeCHM;

        else if (![ext compare:@"zip" options:kCFCompareCaseInsensitive ])
            type = kTextFileTypeZIP;

        else if (![ext compare:@"rar" options:kCFCompareCaseInsensitive ])
            type = kTextFileTypeRAR;

    }
    else if ([fileName length] > 5 &&
             [fileName characterAtIndex:[fileName length]-5] == '.')
    {
        NSString * ext = [fileName substringFromIndex:[fileName length]-4];

        if (![ext compare:@"text" options:kCFCompareCaseInsensitive ])
            type = kTextFileTypeTXT;

        else if (![ext compare:@"html" options:kCFCompareCaseInsensitive ])
            type = kTextFileTypeHTML;

        else if (![ext compare:@"mobi" options:kCFCompareCaseInsensitive ])
            type = kTextFileTypePDB;
    }

    if (type == kTextFileTypeUnknown &&
        [fileName length] > ([TEXTREADER_CACHE_EXT length]+1) &&
        [fileName characterAtIndex:[fileName length]-([TEXTREADER_CACHE_EXT length]+1)] == '.')
    {
        NSString * ext = [fileName substringFromIndex:[fileName length]-[TEXTREADER_CACHE_EXT length]];

        if (![ext compare:TEXTREADER_CACHE_EXT options:kCFCompareCaseInsensitive ])
            type = kTextFileTypeTRCache;
    }

    return type;

} // getFileType










// Utility file for handling covert art images
- (NSString *) checkForImage:(NSString *)file ext:(NSString *)ext path:(NSString*)path {

   NSString * fpath = [path stringByAppendingPathComponent:[file stringByAppendingPathExtension:ext]];

   if ([[NSFileManager defaultManager] fileExistsAtPath:fpath])
      return fpath;

   return nil;

} // checkForImage


// Figure out the name of the cover art file, if any ...
- (NSString *) getCoverArt:(NSString *)fname path:(NSString*)path {

    NSString * iname = nil;

    NSString * extstrip = [fname stringByDeletingPathExtension];

    // Need to do 2 stips for cache files ...
    if ([self getFileType:fname] == kTextFileTypeTRCache)
        extstrip = [extstrip stringByDeletingPathExtension];

    if ([self getShowCoverArt])
    {
        iname = [self checkForImage:extstrip ext:@"jpg" path:path];
        if (!iname)
            iname = [self checkForImage:extstrip ext:@"png" path:path];
        if (!iname)
            iname = [self checkForImage:@"cover" ext:@"jpg" path:path];
        if (!iname)
            iname = [self checkForImage:@"cover" ext:@"png" path:path];
        if (!iname)
            iname = [self checkForImage:extstrip ext:@"JPG" path:path];
        if (!iname)
            iname = [self checkForImage:extstrip ext:@"PNG" path:path];
        if (!iname)
            iname = [self checkForImage:@"cover" ext:@"JPG" path:path];
        if (!iname)
            iname = [self checkForImage:@"cover" ext:@"PNG" path:path];
    }

    return iname;

} // getCoverArt


// Scale image view to fit in height/width and center
// Used for coverart and file open table icons
- (void) scaleImage:(UIImageView*)image maxheight:(int)maxheight maxwidth:(int)maxwidth yOffset:(int)yOffset {

    // Get image size
    float iwidth  = CGImageGetWidth([image.image CGImage]);
    float iheight = CGImageGetHeight([image.image CGImage]);

    // shorten or squeeze?
    if (iheight > maxheight)
    {
        iwidth = iwidth * maxheight / iheight;
        iheight = maxheight;
    }

    if (iwidth > maxwidth)
    {
        iheight = iheight * maxwidth / iwidth;
        iwidth = maxwidth;
    }

    [image setFrame:CGRectMake((maxwidth - iwidth)/2,
                               (maxheight - iheight)/2 + yOffset,
                               iwidth, iheight)];

} // scaleImage



int sortFiles(id str1, id str2, void *ctx)
{
    return [str1 compare:str2 options:NSCaseInsensitiveSearch|NSNumericSearch];
} // sortFiles


- (NSMutableArray *) getVisibleFiles:(NSString *)path {

    // Add files
    NSMutableArray * files = [ [ NSMutableArray alloc] init ];

    NSArray *  contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
    int i;
    for (i = 0; i < [contents count]; i++)
    {
        NSString * file = [contents  objectAtIndex:i];

        // Only add the file if we can open it ...
        if ([self isVisibleFile:file path:path])
            [files addObject:file];
    }

    // Sort the list so files are in order
    // file 1, file 2, ... file 10, file 11, ...
    [files sortUsingFunction:&sortFiles context:NULL];

    return files;

} // getVisibleFiles
- (void)applicationWillResignActive:(UIApplication *)application {
    /*
     Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
     Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
     */
}


- (void)applicationDidEnterBackground:(UIApplication *)application {
    /*
     Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
     If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
     */
}


- (void)applicationWillEnterForeground:(UIApplication *)application {
    /*
     Called as part of  transition from the background to the inactive state: here you can undo many of the changes made on entering the background.
     */
}


- (void)applicationDidBecomeActive:(UIApplication *)application {
    /*
     Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
     */
}




#pragma mark -
#pragma mark Memory management

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
    /*
     Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.
     */
}

- (void)dealloc {
	[baseTextViewController release];
	[navigationController release];
	[mainWindow release];
	[_fileTable release];
	[super dealloc];
}

@end // @implementation textReader






